home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 748 / 748.xpi / content / scriptdownloader.js < prev    next >
Text File  |  2010-02-11  |  9KB  |  291 lines

  1. // This anonymous function exists to isolate generic names inside it to its
  2. // private scope.
  3. (function() {
  4.  
  5. function ScriptDownloader(win, uri, bundle) {
  6.   this.win_ = win;
  7.   this.uri_ = uri;
  8.   this.bundle_ = bundle;
  9.   this.req_ = null;
  10.   this.script = null;
  11.   this.depQueue_ = [];
  12.   this.dependenciesLoaded_ = false;
  13.   this.installOnCompletion_ = false;
  14.   this.tempFiles_ = [];
  15. }
  16.  
  17. // Export this one important value to the global namespace.
  18. window.GM_ScriptDownloader=ScriptDownloader;
  19.  
  20. ScriptDownloader.prototype.startInstall = function() {
  21.   this.installing_ = true;
  22.   this.startDownload();
  23. };
  24.  
  25. ScriptDownloader.prototype.startViewScript = function(uri) {
  26.   this.installing_ = false;
  27.   this.startDownload();
  28. };
  29.  
  30. ScriptDownloader.prototype.startDownload = function() {
  31.   this.win_.GM_BrowserUI.statusImage.src = "chrome://global/skin/throbber/Throbber-small.gif";
  32.   this.win_.GM_BrowserUI.statusImage.style.opacity = "0.5";
  33.   this.win_.GM_BrowserUI.statusImage.tooltipText = this.bundle_.getString("tooltip.loading");
  34.  
  35.   this.win_.GM_BrowserUI.showStatus("Fetching user script", false);
  36.  
  37.   Components.classes["@greasemonkey.mozdev.org/greasemonkey-service;1"]
  38.     .getService().wrappedJSObject
  39.     .ignoreNextScript();
  40.  
  41.   this.req_ = new XMLHttpRequest();
  42.   this.req_.open("GET", this.uri_.spec, true);
  43.   this.req_.onload = GM_hitch(this, "handleScriptDownloadComplete");
  44.   this.req_.send(null);
  45. };
  46.  
  47. ScriptDownloader.prototype.handleScriptDownloadComplete = function() {
  48.   this.win_.GM_BrowserUI.refreshStatus();
  49.   this.win_.GM_BrowserUI.hideStatusImmediately();
  50.  
  51.   try {
  52.     // If loading from file, status might be zero on success
  53.     if (this.req_.status != 200 && this.req_.status != 0) {
  54.       // NOTE: Unlocalized string
  55.       alert("Error loading user script:\n" +
  56.       this.req_.status + ": " +
  57.       this.req_.statusText);
  58.       return;
  59.     }
  60.  
  61.     var source = this.req_.responseText;
  62.  
  63.     this.script = GM_getConfig().parse(source, this.uri_);
  64.  
  65.     var file = Components.classes["@mozilla.org/file/directory_service;1"]
  66.                          .getService(Components.interfaces.nsIProperties)
  67.                          .get("TmpD", Components.interfaces.nsILocalFile);
  68.  
  69.     var base = this.script.name.replace(/[^A-Z0-9_]/gi, "").toLowerCase();
  70.     file.append(base + ".user.js");
  71.     file.createUnique(
  72.       Components.interfaces.nsILocalFile.NORMAL_FILE_TYPE,
  73.       0640
  74.     );
  75.     this.tempFiles_.push(file);
  76.  
  77.     var converter =
  78.       Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
  79.         .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
  80.     converter.charset = "UTF-8";
  81.     source = converter.ConvertFromUnicode(source);
  82.  
  83.     var ws = getWriteStream(file);
  84.     ws.write(source, source.length);
  85.     ws.close();
  86.  
  87.     this.script.setDownloadedFile(file);
  88.  
  89.     window.setTimeout(GM_hitch(this, "fetchDependencies"), 0);
  90.  
  91.     if(this.installing_){
  92.       this.showInstallDialog();
  93.     }else{
  94.       this.showScriptView();
  95.     }
  96.   } catch (e) {
  97.     // NOTE: unlocalized string
  98.     alert("Script could not be installed " + e);
  99.     throw e;
  100.   }
  101. };
  102.  
  103. ScriptDownloader.prototype.fetchDependencies = function(){
  104.   GM_log("Fetching Dependencies");
  105.   var deps = this.script.requires.concat(this.script.resources);
  106.   for (var i = 0; i < deps.length; i++) {
  107.     var dep = deps[i];
  108.     if (this.checkDependencyURL(dep.urlToDownload)) {
  109.       this.depQueue_.push(dep);
  110.     } else {
  111.       this.errorInstallDependency(this.script, dep,
  112.         "SecurityException: Request to local and chrome url's is forbidden");
  113.       return;
  114.     }
  115.   }
  116.   this.downloadNextDependency();
  117. };
  118.  
  119. ScriptDownloader.prototype.downloadNextDependency = function(){
  120.   if (this.depQueue_.length > 0) {
  121.     var dep = this.depQueue_.pop();
  122.     try {
  123.       var persist = Components.classes[
  124.         "@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
  125.         .createInstance(Components.interfaces.nsIWebBrowserPersist);
  126.       persist.persistFlags =
  127.         persist.PERSIST_FLAGS_BYPASS_CACHE |
  128.         persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES; //doesn't work?
  129.       var ioservice =
  130.         Components.classes["@mozilla.org/network/io-service;1"]
  131.         .getService(Components.interfaces.nsIIOService);
  132.       var sourceUri = ioservice.newURI(dep.urlToDownload, null, null);
  133.       var sourceChannel = ioservice.newChannelFromURI(sourceUri);
  134.       sourceChannel.notificationCallbacks = new NotificationCallbacks();
  135.  
  136.       var file = getTempFile();
  137.       this.tempFiles_.push(file);
  138.  
  139.       var progressListener = new PersistProgressListener(persist);
  140.       progressListener.onFinish = GM_hitch(this,
  141.         "handleDependencyDownloadComplete", dep, file, sourceChannel);
  142.       persist.progressListener = progressListener;
  143.  
  144.       persist.saveChannel(sourceChannel,  file);
  145.     } catch(e) {
  146.       GM_log("Download exception " + e);
  147.       this.errorInstallDependency(this.script, dep, e);
  148.     }
  149.   } else {
  150.     this.dependenciesLoaded_ = true;
  151.     this.finishInstall();
  152.   }
  153. };
  154.  
  155. ScriptDownloader.prototype.handleDependencyDownloadComplete =
  156. function(dep, file, channel) {
  157.   GM_log("Dependency Download complete " + dep.urlToDownload);
  158.   try {
  159.     var httpChannel =
  160.       channel.QueryInterface(Components.interfaces.nsIHttpChannel);
  161.   } catch(e) {
  162.     var httpChannel = false;
  163.   }
  164.  
  165.   if (httpChannel) {
  166.     if (httpChannel.requestSucceeded) {
  167.       dep.setDownloadedFile(file, channel.contentType, channel.contentCharset ? channel.contentCharset : null);
  168.       this.downloadNextDependency();
  169.     } else {
  170.       this.errorInstallDependency(this.script, dep,
  171.         "Error! Server Returned : " + httpChannel.responseStatus + ": " +
  172.         httpChannel.responseStatusText);
  173.     }
  174.   } else {
  175.     dep.setDownloadedFile(file);
  176.     this.downloadNextDependency();
  177.   }
  178. };
  179.  
  180. ScriptDownloader.prototype.checkDependencyURL = function(url) {
  181.   var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  182.                             .getService(Components.interfaces.nsIIOService);
  183.   var scheme = ioService.extractScheme(url);
  184.  
  185.   switch (scheme) {
  186.     case "http":
  187.     case "https":
  188.     case "ftp":
  189.         return true;
  190.     case "file":
  191.         var scriptScheme = ioService.extractScheme(this.uri_.spec);
  192.         return (scriptScheme == "file")
  193.     default:
  194.       return false;
  195.   }
  196. };
  197.  
  198. ScriptDownloader.prototype.finishInstall = function(){
  199.   if (this.installOnCompletion_) {
  200.     this.installScript();
  201.   }
  202. };
  203.  
  204. ScriptDownloader.prototype.errorInstallDependency = function(script, dep, msg){
  205.   GM_log("Error loading dependency " + dep.urlToDownload + "\n" + msg)
  206.   if (this.installOnCompletion_) {
  207.     alert("Error loading dependency " + dep.urlToDownload + "\n" + msg);
  208.   } else {
  209.     this.dependencyError = "Error loading dependency " + dep.urlToDownload + "\n" + msg;
  210.   }
  211. };
  212.  
  213. ScriptDownloader.prototype.installScript = function(){
  214.   if (this.dependencyError) {
  215.     alert(this.dependencyError);
  216.   } else if(this.dependenciesLoaded_) {
  217.     this.win_.GM_BrowserUI.installScript(this.script)
  218.   } else {
  219.     this.installOnCompletion_ = true;
  220.   }
  221. };
  222.  
  223. ScriptDownloader.prototype.cleanupTempFiles = function() {
  224.   for (var i = 0, file = null; file = this.tempFiles_[i]; i++) {
  225.     file.remove(false);
  226.   }
  227. };
  228.  
  229. ScriptDownloader.prototype.showInstallDialog = function(timer) {
  230.   if (!timer) {
  231.     // otherwise, the status bar stays in the loading state.
  232.     this.win_.setTimeout(GM_hitch(this, "showInstallDialog", true), 0);
  233.     return;
  234.   }
  235.   this.win_.openDialog("chrome://greasemonkey/content/install.xul", "",
  236.                        "chrome,centerscreen,modal,dialog,titlebar,resizable",
  237.                        this);
  238. };
  239.  
  240. ScriptDownloader.prototype.showScriptView = function() {
  241.   this.win_.GM_BrowserUI.showScriptView(this);
  242. };
  243.  
  244. function NotificationCallbacks() {}
  245.  
  246. NotificationCallbacks.prototype.QueryInterface = function(aIID) {
  247.   if (aIID.equals(Components.interfaces.nsIInterfaceRequestor)) {
  248.     return this;
  249.   }
  250.   throw Components.results.NS_NOINTERFACE;
  251. };
  252.  
  253. NotificationCallbacks.prototype.getInterface = function(aIID) {
  254.   if (aIID.equals(Components.interfaces.nsIAuthPrompt )) {
  255.      var winWat = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
  256.                             .getService(Components.interfaces.nsIWindowWatcher);
  257.      return winWat.getNewAuthPrompter(winWat.activeWindow);
  258.   }
  259.   return undefined;
  260. };
  261.  
  262.  
  263. function PersistProgressListener(persist) {
  264.   this.persist = persist;
  265.   this.onFinish = function(){};
  266.   this.persiststate = "";
  267. }
  268.  
  269. PersistProgressListener.prototype.QueryInterface = function(aIID) {
  270.  if (aIID.equals(Components.interfaces.nsIWebProgressListener)) {
  271.    return this;
  272.  }
  273.  throw Components.results.NS_NOINTERFACE;
  274. };
  275.  
  276. // nsIWebProgressListener
  277. PersistProgressListener.prototype.onProgressChange =
  278.   PersistProgressListener.prototype.onLocationChange =
  279.     PersistProgressListener.prototype.onStatusChange =
  280.       PersistProgressListener.prototype.onSecurityChange = function(){};
  281.  
  282. PersistProgressListener.prototype.onStateChange =
  283.   function(aWebProgress, aRequest, aStateFlags, aStatus) {
  284.     if (this.persist.currentState == this.persist.PERSIST_STATE_FINISHED) {
  285.       GM_log("Persister: Download complete " + aRequest.status);
  286.       this.onFinish();
  287.     }
  288.   };
  289.  
  290. })();
  291.